package com.invengo.library_rfid.analyze.utils.hf;
import java.util.ArrayList;
import java.util.List;

import me.goldze.mvvmhabit.utils.KLog;

public class HFDataFormat {
    public static String Deserialise(String epc) {
        KLog.e(epc+"----");
        String Code = "";
        List<EpcComposition> epcCompositions = Analysis(epc);
        for (EpcComposition epcComposition : epcCompositions) {
            switch (epcComposition.getOid()) {
                case 1:
                    Code = Decompress(StringToByteArray(epcComposition.getContent()), epcComposition.getCompressMode(), epcComposition.getOid());
                    break;
                case 2:
                    continue;
                case 3:
                    try {
                        String LibraryCode = Decompress(StringToByteArray(epcComposition.getContent()), epcComposition.getCompressMode(), epcComposition.getOid());
                    } catch (Exception e) {
                    }
                    break;
            }
        }
        return Code;
    }

    static List<EpcComposition> Analysis(String epc) {
        if (epc == null || epc.isEmpty() || epc.startsWith("000000")) return null;
        List<EpcComposition> epcCompositions = new ArrayList<>();
        try {
            int i = 0;
            while (i < epc.length()) {
                if (i + 4 >= epc.length()) break;
                EpcComposition epcComposition = new EpcComposition();
                String firstCharBin = HexString2BinString(String.valueOf(epc.charAt(i)));
                epcComposition.setIsFill(firstCharBin.startsWith("1"));
                epcComposition.setCompressMode(Integer.parseInt(('0' + firstCharBin.substring(1)).trim(), 2));
                epcComposition.setOid(Integer.parseInt(epc.substring(i + 1, i + 2)));
                if (epcComposition.getOid() == 0) break;
                if (epcComposition.getIsFill()) {
                    epcComposition.setFillLength(Integer.parseInt(epc.substring(i + 2, i + 4)));
                    epcComposition.setContentLength(Integer.parseInt(epc.substring(i + 4, i + 6), 16));
                    epcComposition.setContent(epc.substring(i + 6, i + 6 + epcComposition.getContentLength() * 2));
                    i += 6 + epcComposition.getContentLength() * 2 + (int) epcComposition.getFillLength() * 2;
                } else {
                    epcComposition.setContentLength(Integer.parseInt(epc.substring(i + 2, i + 4), 16));
                    epcComposition.setContent(epc.substring(i + 4, i + 4 + epcComposition.getContentLength() * 2));
                    i += 4 + epcComposition.getContentLength() * 2;
                }
                epcCompositions.add(epcComposition);
            }
            return epcCompositions;
        } catch (Exception ex) {
            return null;
        }
    }

    static String Decompress(byte[] data, int mode, int oid) {
        String result;
        switch (mode) {
            case 0:
                if (oid == 3) {
                    result = DecompressISIL(data);
                } else {
                    result = DecompressAscii(data);
                }
                break;
            case 1:
                String hex = ByteArrayToHexString(data).trim();
                result = String.valueOf(Long.parseLong(hex, 16)).trim();
                break;
            case 2:
                result = ByteArrayToHexString(data).toUpperCase().trim().replaceAll("F", "");
                break;
            case 3:
                result = Decompress5bit(data);
                break;
            case 4:
                result = Decompress6bit(data);
                break;
            case 5:
                result = Decompress7bit(data);
                break;
            case 6:
                result = DecompressAscii(data);
                break;
            default:
                result = ByteArrayToHexString(data);
                break;
        }
        return result;
    }

    static String DecompressISIL(byte[] data) {
        String binStr = "";
        for (byte item : data) {
            binStr += String.format("%8s", Integer.toBinaryString(item & 0xFF)).replace(' ', '0');
        }
        String result = "";
        int i = 0;
        String currentOffsetStr = "010";
        String oldOffsetStr = "010";
        boolean isLock = true;
        while (i < binStr.length()) {
            if (binStr.length() - i < 4) break;
            String binContent;
            if (!currentOffsetStr.equals("0011")) {
                if (i + 5 > binStr.length()) break;
                binContent = binStr.substring(i, i + 5);
                i += 5;
                if (binContent.startsWith("111")) {
                    isLock = binContent.endsWith("0");
                    oldOffsetStr = currentOffsetStr;
                    if (currentOffsetStr.equals("010")) {
                        currentOffsetStr = binContent.substring(3, 4).equals("0") ? "011" : "0011";
                    } else {
                        currentOffsetStr = binContent.substring(3, 4).equals("0") ? "010" : "0011";
                    }
                    continue;
                }
            } else {
                binContent = binStr.substring(i, i + 4);
                i += 4;
                if (binContent.startsWith("11")) {
                    isLock = binContent.endsWith("0");
                    oldOffsetStr = currentOffsetStr;
                    currentOffsetStr = binContent.substring(2, 3).equals("0") ? "010" : "011";
                    continue;
                }
            }
            if (currentOffsetStr.equals("010")) {
                if (binContent.equals("00000")) {
                    result += "-";
                    if (!isLock) {
                        currentOffsetStr = oldOffsetStr;
                    }
                    continue;
                }
                if (binContent.equals("11011")) {
                    result += ":";
                    if (!isLock) {
                        currentOffsetStr = oldOffsetStr;
                    }
                    continue;
                }
                result += (char) Integer.parseInt(currentOffsetStr + binContent, 2);
                if (!isLock) {
                    currentOffsetStr = oldOffsetStr;
                }
            } else if (currentOffsetStr.equals("011")) {
                if (binContent.equals("00000")) {
                    result += "-";
                    if (!isLock) {
                        currentOffsetStr = oldOffsetStr;
                    }
                    continue;
                }
                if (binContent.equals("11011")) {
                    result += "/";
                    if (!isLock) {
                        currentOffsetStr = oldOffsetStr;
                    }
                    continue;
                }
                result += (char) Integer.parseInt(currentOffsetStr + binContent, 2);
                if (!isLock) {
                    currentOffsetStr = oldOffsetStr;
                }
            } else {
                if (binContent.equals("1010")) {
                    result += "-";
                    if (!isLock) {
                        currentOffsetStr = oldOffsetStr;
                    }
                    continue;
                }
                if (binContent.equals("1011")) {
                    result += ":";
                    if (!isLock) {
                        currentOffsetStr = oldOffsetStr;
                    }
                    continue;
                }
                result += (char) Integer.parseInt(currentOffsetStr + binContent, 2);
                if (!isLock) {
                    currentOffsetStr = oldOffsetStr;
                }
            }
        }
        return result;
    }

    static String DecompressAscii(byte[] data) {
        if (data == null) {
            return "";
        }
        StringBuilder hexStringBuilder = new StringBuilder(data.length);
        for (byte b : data) {
            if (b == 0x00) {
                continue;
            }
            hexStringBuilder.append((char) b);
        }
        return hexStringBuilder.toString().trim();
    }

    static String Decompress5bit(byte[] data) {
        String tmpStr = "";
        for (byte item : data) {
            tmpStr += String.format("%8s", Integer.toBinaryString(item & 0xFF)).replace(' ', '0');
        }
        String tmpResult = "";
        for (int i = 0; i < tmpStr.length(); i += 5) {
            if (tmpStr.length() - i > 5) {
                String hexStr = String.format("%x", Integer.parseInt("010" + tmpStr.substring(i, i + 5), 2));
                if (!hexStr.matches("^[A-_]+$")) {
                    tmpResult += hexStr;
                }
            }
        }
        return tmpResult;
    }

    static String Decompress6bit(byte[] data) {
        StringBuilder binaryStrs = new StringBuilder();
        for (byte by : data) {
            binaryStrs.append(String.format("%8s", Integer.toBinaryString(by & 0xFF)).replace(' ', '0'));
        }
        String str = binaryStrs.toString();
        str = str.substring(0, (str.length() - str.length() % 6));
        String tmp = "";
        String barcode = "";
        int charCount = 0;
        for (char c : str.toCharArray()) {
            tmp += c;
            charCount += 1;
            if (charCount % 6 == 0) {
                tmp = tmp.startsWith("1") ? "00" + tmp : "01" + tmp;
                barcode += (char) (Integer.parseInt(tmp, 2));
                tmp = "";
            }
        }
        return barcode.trim();
    }

    static String Decompress7bit(byte[] data) {
        String tmpStr = "";
        for (byte item : data) {
            tmpStr += String.format("%8s", Integer.toBinaryString(item & 0xFF)).replace(' ', '0');
        }
        String tmpResult = "";
        for (int i = 0; i < tmpStr.length(); i += 7) {
            if (tmpStr.length() - i > 7) {
                String hexStr = String.format("%x", Integer.parseInt("0" + tmpStr.substring(i, i + 7), 2));
                if (!hexStr.matches("^[\u0000-\u007E]+$")) {
                    tmpResult += hexStr;
                }
            }
        }
        return tmpResult;
    }

    static byte[] StringToByteArray(String strHex) {
        try {
            strHex = strHex.length() % 2 == 0 ? strHex : "0" + strHex.trim();
            List<Byte> bytes = new ArrayList<>();
            for (int i = 0; i < strHex.length(); i += 2) {
                bytes.add((byte) Integer.parseInt(strHex.substring(i, i + 2), 16));
            }
            byte[] byteArray = new byte[bytes.size()];
            for (int i = 0; i < bytes.size(); i++) {
                byteArray[i] = bytes.get(i);
            }
            return byteArray;
        } catch (Exception ex) {
            throw ex;
        }
    }

    static String HexString2BinString(String hexString) {
        StringBuilder result = new StringBuilder();
        for (char c : hexString.toCharArray()) {
            int v = Integer.parseInt(String.valueOf(c), 16);
            int v2 = Integer.parseInt(Integer.toString(v, 2));
            result.append(String.format("%4s", v2).replace(' ', '0'));
        }
        return result.toString();
    }

    static String ByteArrayToHexString(byte[] data) {
        StringBuilder stringBuilder = new StringBuilder(data.length * 3);
        for (byte b : data) {
            stringBuilder.append(String.format("%02x", b));
        }
        return stringBuilder.toString().toUpperCase();
    }
}



